{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "eb11dfbe-6455-4bda-9fb1-c27cc7e03cda",
   "metadata": {},
   "source": [
    "# Mashup Recsys Baseline"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f02ab53-962f-47ad-b467-7c698bd11540",
   "metadata": {},
   "source": [
    "[TOC]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "id": "310aabc9-a064-4a30-ad43-43dbf3ecbdae",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "from tqdm.notebook import tqdm\n",
    "import numpy as np\n",
    "from sklearn.feature_extraction.text import TfidfVectorizer\n",
    "from sklearn.metrics.pairwise import cosine_similarity\n",
    "import heapq\n",
    "from transformers import AutoTokenizer, AutoModel\n",
    "import torch"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c51cfa47-3ce6-454e-9f4d-2b2d9eda120c",
   "metadata": {},
   "source": [
    "## Prepare Data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "948f3d81-f1ea-4842-a660-0b1c4bf44a44",
   "metadata": {},
   "source": [
    "### Load data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "28439461-9c5b-4721-91d5-696c7d26f44c",
   "metadata": {},
   "outputs": [],
   "source": [
    "mashup = pd.read_pickle('mashup_df.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "bf3aba1c-9439-4182-aaf9-a27892a21e03",
   "metadata": {},
   "outputs": [],
   "source": [
    "mashup['Related APIs'] = mashup['Related APIs'].map(lambda x: [y.strip() for y in x.split(',')] if x is not None else [])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "984b10ea-f5eb-46b1-803c-97ad1d3838cc",
   "metadata": {},
   "outputs": [],
   "source": [
    "mashup_non_trivial = mashup[mashup['Related APIs'].map(len) > 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "db531933-8faa-4266-b69c-2df68628e708",
   "metadata": {},
   "outputs": [],
   "source": [
    "api = pd.read_pickle('api_df.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "13f7d948-ea2a-4498-b725-0a2478371cc5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>mashup_name</th>\n",
       "      <th>Related APIs</th>\n",
       "      <th>Categories</th>\n",
       "      <th>URL</th>\n",
       "      <th>Company</th>\n",
       "      <th>Mashup/App Type</th>\n",
       "      <th>Description</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Twitwhere</td>\n",
       "      <td>[Twitter, Google Earth, Google App Engine]</td>\n",
       "      <td>Mapping, Social, Visualizations</td>\n",
       "      <td>http://twitwhere.appspot.com</td>\n",
       "      <td>None</td>\n",
       "      <td>None</td>\n",
       "      <td>This Service is a mashup service using twitter...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>PetStew.com</td>\n",
       "      <td>[Flickr, Amazon Product Advertising, Google Ma...</td>\n",
       "      <td>Pets, Pets, Classifieds, Video, Photos, eCommerce</td>\n",
       "      <td>http://www.petstew.com/index.html</td>\n",
       "      <td>None</td>\n",
       "      <td>None</td>\n",
       "      <td>A pet site providing classifieds, adoptions, p...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>Audio Transcription</td>\n",
       "      <td>[US Yellow Pages, Yahoo My Web Search]</td>\n",
       "      <td>Transcription, Accessibility</td>\n",
       "      <td>http://transcriptionplace.com/audio-book-trans...</td>\n",
       "      <td>None</td>\n",
       "      <td>None</td>\n",
       "      <td>Transcription supports accessibility. Persons ...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>CityClash</td>\n",
       "      <td>[Google Maps, Google Cloud Translation, Google...</td>\n",
       "      <td>Social, Ratings, Ratings, Travel, Real Estate,...</td>\n",
       "      <td>http://www.cityclash.org/</td>\n",
       "      <td>None</td>\n",
       "      <td>None</td>\n",
       "      <td>City ratings and rankings by people.</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>Moveable History</td>\n",
       "      <td>[Wikipedia, Tropo Scripting, Voxeo, Google Lat...</td>\n",
       "      <td>Mobile, Voice, Mapping, History</td>\n",
       "      <td>http://moveable-weather.appspot.com/history_demo</td>\n",
       "      <td>None</td>\n",
       "      <td>None</td>\n",
       "      <td>This is the 3rd in the \"moveable\" series, that...</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "           mashup_name                                       Related APIs  \\\n",
       "0            Twitwhere         [Twitter, Google Earth, Google App Engine]   \n",
       "4          PetStew.com  [Flickr, Amazon Product Advertising, Google Ma...   \n",
       "5  Audio Transcription             [US Yellow Pages, Yahoo My Web Search]   \n",
       "6            CityClash  [Google Maps, Google Cloud Translation, Google...   \n",
       "7     Moveable History  [Wikipedia, Tropo Scripting, Voxeo, Google Lat...   \n",
       "\n",
       "                                          Categories  \\\n",
       "0                    Mapping, Social, Visualizations   \n",
       "4  Pets, Pets, Classifieds, Video, Photos, eCommerce   \n",
       "5                       Transcription, Accessibility   \n",
       "6  Social, Ratings, Ratings, Travel, Real Estate,...   \n",
       "7                    Mobile, Voice, Mapping, History   \n",
       "\n",
       "                                                 URL Company Mashup/App Type  \\\n",
       "0                       http://twitwhere.appspot.com    None            None   \n",
       "4                  http://www.petstew.com/index.html    None            None   \n",
       "5  http://transcriptionplace.com/audio-book-trans...    None            None   \n",
       "6                          http://www.cityclash.org/    None            None   \n",
       "7   http://moveable-weather.appspot.com/history_demo    None            None   \n",
       "\n",
       "                                         Description  \n",
       "0  This Service is a mashup service using twitter...  \n",
       "4  A pet site providing classifieds, adoptions, p...  \n",
       "5  Transcription supports accessibility. Persons ...  \n",
       "6               City ratings and rankings by people.  \n",
       "7  This is the 3rd in the \"moveable\" series, that...  "
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mashup_non_trivial.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "56f1624e-3f55-43f3-9180-3dfc68298898",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>api_name</th>\n",
       "      <th>api_text</th>\n",
       "      <th>api_tag</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>WordPress.org</td>\n",
       "      <td>WordPress.org is home of the installable versi...</td>\n",
       "      <td>[Blogging, Social, Content Management]</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Lulu Publishing</td>\n",
       "      <td>The Lulu Print API allows you to use Lulu.com ...</td>\n",
       "      <td>[Printing, B2B, Books, eCommerce, Printing, Pu...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>EveryTrail</td>\n",
       "      <td>EveryTrail is a platform that allows users to ...</td>\n",
       "      <td>[Travel, Sports, Social, Mapping, Mapping]</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Lightspeed Retail</td>\n",
       "      <td>Lightspeed Retail API allows developers to int...</td>\n",
       "      <td>[Sales, eCommerce, Engagement, Inventory, Prod...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Google Wave</td>\n",
       "      <td>Google Wave is a product that helps users comm...</td>\n",
       "      <td>[Social, Widgets, Blogging, Robots, Gadgets]</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            api_name                                           api_text  \\\n",
       "0      WordPress.org  WordPress.org is home of the installable versi...   \n",
       "1    Lulu Publishing  The Lulu Print API allows you to use Lulu.com ...   \n",
       "2         EveryTrail  EveryTrail is a platform that allows users to ...   \n",
       "3  Lightspeed Retail  Lightspeed Retail API allows developers to int...   \n",
       "4        Google Wave  Google Wave is a product that helps users comm...   \n",
       "\n",
       "                                             api_tag  \n",
       "0             [Blogging, Social, Content Management]  \n",
       "1  [Printing, B2B, Books, eCommerce, Printing, Pu...  \n",
       "2         [Travel, Sports, Social, Mapping, Mapping]  \n",
       "3  [Sales, eCommerce, Engagement, Inventory, Prod...  \n",
       "4       [Social, Widgets, Blogging, Robots, Gadgets]  "
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "api.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "f950d9be-ddf5-4d59-8a77-a701b240f86a",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('api_8459.json', 'r', encoding='utf8') as f:\n",
    "    api_new = json.load(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "id": "eb10c3c6-e14a-43c7-b1b0-37feb65c4a65",
   "metadata": {},
   "outputs": [],
   "source": [
    "api_new_df = pd.DataFrame(api_new)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "7be32ad8-9410-493f-9180-a1ceeb78fd75",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>api_id</th>\n",
       "      <th>api_name</th>\n",
       "      <th>api_prim_cate</th>\n",
       "      <th>api_desc</th>\n",
       "      <th>n_followers</th>\n",
       "      <th>n_appear_in_mashup</th>\n",
       "      <th>order</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>72087</td>\n",
       "      <td>WebPay Direct</td>\n",
       "      <td>4</td>\n",
       "      <td>webteh is croatian based iso/msp/psp registere...</td>\n",
       "      <td>9</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>63420</td>\n",
       "      <td>BeenVerified</td>\n",
       "      <td>11</td>\n",
       "      <td>from their site: the beenverified com api foll...</td>\n",
       "      <td>17</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>188798</td>\n",
       "      <td>PayPlug</td>\n",
       "      <td>4</td>\n",
       "      <td>the payplug api integrates payments into websi...</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>70981</td>\n",
       "      <td>Mozilla Persona</td>\n",
       "      <td>11</td>\n",
       "      <td>mozilla persona is an online identity service ...</td>\n",
       "      <td>4</td>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>71471</td>\n",
       "      <td>BODC Marsden Square Translator Service</td>\n",
       "      <td>7</td>\n",
       "      <td>the british oceanographic data centre bodc is ...</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   api_id                                api_name  api_prim_cate  \\\n",
       "0   72087                           WebPay Direct              4   \n",
       "1   63420                            BeenVerified             11   \n",
       "2  188798                                 PayPlug              4   \n",
       "3   70981                         Mozilla Persona             11   \n",
       "4   71471  BODC Marsden Square Translator Service              7   \n",
       "\n",
       "                                            api_desc  n_followers  \\\n",
       "0  webteh is croatian based iso/msp/psp registere...            9   \n",
       "1  from their site: the beenverified com api foll...           17   \n",
       "2  the payplug api integrates payments into websi...            3   \n",
       "3  mozilla persona is an online identity service ...            4   \n",
       "4  the british oceanographic data centre bodc is ...            3   \n",
       "\n",
       "   n_appear_in_mashup  order  \n",
       "0                   0      0  \n",
       "1                   1      1  \n",
       "2                   0      2  \n",
       "3                   0      3  \n",
       "4                   0      4  "
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "api_new_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "id": "82a9ce51-1424-4647-b49b-681b4ffb7dd8",
   "metadata": {},
   "outputs": [],
   "source": [
    "api_2 = pd.read_csv('api.csv', index_col=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "id": "3722ca9b-9c78-470f-9258-7327d5250906",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Name</th>\n",
       "      <th>Desc</th>\n",
       "      <th>Primary Category</th>\n",
       "      <th>Followers</th>\n",
       "      <th>Secondary Categories</th>\n",
       "      <th>API Provider</th>\n",
       "      <th>API Endpoint</th>\n",
       "      <th>API Portal / Home Page</th>\n",
       "      <th>Docs Home Page URL</th>\n",
       "      <th>Terms Of Service URL</th>\n",
       "      <th>Supported Request Formats</th>\n",
       "      <th>Supported Response Formats</th>\n",
       "      <th>Is This an Unofficial API?</th>\n",
       "      <th>Is the API Design/Description Non-Proprietary ?</th>\n",
       "      <th>Restricted Access ( Requires Provider Approval )</th>\n",
       "      <th>Is This a Hypermedia API?</th>\n",
       "      <th>SSL Support</th>\n",
       "      <th>Architectural Style</th>\n",
       "      <th>Twitter URL</th>\n",
       "      <th>Authentication Model</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Google Maps</td>\n",
       "      <td>The Google Maps API allow for the embedding of...</td>\n",
       "      <td>Mapping</td>\n",
       "      <td>3781</td>\n",
       "      <td>Viewer</td>\n",
       "      <td>Google</td>\n",
       "      <td>https://www.google.com/maps/embed/v1/</td>\n",
       "      <td>https://developers.google.com/maps/</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>URI Query String/CRUD, VML, JavaScript</td>\n",
       "      <td>JSON, KML, XML</td>\n",
       "      <td>No</td>\n",
       "      <td>No</td>\n",
       "      <td>No</td>\n",
       "      <td>Yes</td>\n",
       "      <td>No</td>\n",
       "      <td>REST</td>\n",
       "      <td>http://twitter.com/googlemapsapi</td>\n",
       "      <td>API Key</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Twilio SMS</td>\n",
       "      <td>The Twilio SMS API allows developers to send a...</td>\n",
       "      <td>Messaging</td>\n",
       "      <td>272</td>\n",
       "      <td>Telephony</td>\n",
       "      <td>Twilio</td>\n",
       "      <td>https://api.twilio.com/2010-04-01</td>\n",
       "      <td>https://www.twilio.com/sms/api</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>JSON, URI Query String/CRUD</td>\n",
       "      <td>JSON</td>\n",
       "      <td>No</td>\n",
       "      <td>Yes</td>\n",
       "      <td>No</td>\n",
       "      <td>No</td>\n",
       "      <td>Yes</td>\n",
       "      <td>REST</td>\n",
       "      <td>https://twitter.com/twilio</td>\n",
       "      <td>HTTP Basic Auth, Token</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Facebook</td>\n",
       "      <td>The Facebook API is a platform for building ap...</td>\n",
       "      <td>Social</td>\n",
       "      <td>4133</td>\n",
       "      <td>Webhooks</td>\n",
       "      <td>Facebook</td>\n",
       "      <td>http://api.facebook.com/restserver.php</td>\n",
       "      <td>https://developers.facebook.com/</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>URI Query String/CRUD</td>\n",
       "      <td>CSV, GeoJSON, JSON, XML</td>\n",
       "      <td>No</td>\n",
       "      <td>No</td>\n",
       "      <td>No</td>\n",
       "      <td>Yes</td>\n",
       "      <td>Yes</td>\n",
       "      <td>REST</td>\n",
       "      <td>http://twitter.com/fbplatform</td>\n",
       "      <td>API Key, OAuth 2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Twitter</td>\n",
       "      <td>The Twitter micro-blogging service includes tw...</td>\n",
       "      <td>Social</td>\n",
       "      <td>2336</td>\n",
       "      <td>Blogging</td>\n",
       "      <td>Twitter</td>\n",
       "      <td>http://twitter.com/statuses/</td>\n",
       "      <td>https://developer.twitter.com/en/docs/twitter-...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>URI Query String/CRUD</td>\n",
       "      <td>Atom, RSS, XML</td>\n",
       "      <td>No</td>\n",
       "      <td>Yes</td>\n",
       "      <td>No</td>\n",
       "      <td>Yes</td>\n",
       "      <td>No</td>\n",
       "      <td>FEED</td>\n",
       "      <td>http://twitter.com/twitterapi</td>\n",
       "      <td>OAuth 2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Flickr</td>\n",
       "      <td>The Flickr API can be used to retrieve photos ...</td>\n",
       "      <td>Photos</td>\n",
       "      <td>830</td>\n",
       "      <td>Video</td>\n",
       "      <td>Flickr</td>\n",
       "      <td>http://api.flickr.com/services/</td>\n",
       "      <td>http://www.flickr.com/services/api/</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>URI Query String/CRUD, XML, PHP, XML-RPC</td>\n",
       "      <td>JSON, XML, PHP, XML-RPC</td>\n",
       "      <td>No</td>\n",
       "      <td>No</td>\n",
       "      <td>No</td>\n",
       "      <td>Yes</td>\n",
       "      <td>Yes</td>\n",
       "      <td>REST</td>\n",
       "      <td>https://twitter.com/Flickr</td>\n",
       "      <td>OAuth 1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          Name                                               Desc  \\\n",
       "0  Google Maps  The Google Maps API allow for the embedding of...   \n",
       "1   Twilio SMS  The Twilio SMS API allows developers to send a...   \n",
       "2     Facebook  The Facebook API is a platform for building ap...   \n",
       "3      Twitter  The Twitter micro-blogging service includes tw...   \n",
       "4       Flickr  The Flickr API can be used to retrieve photos ...   \n",
       "\n",
       "  Primary Category  Followers Secondary Categories API Provider  \\\n",
       "0          Mapping       3781               Viewer       Google   \n",
       "1        Messaging        272            Telephony       Twilio   \n",
       "2           Social       4133             Webhooks     Facebook   \n",
       "3           Social       2336             Blogging      Twitter   \n",
       "4           Photos        830                Video       Flickr   \n",
       "\n",
       "                             API Endpoint  \\\n",
       "0   https://www.google.com/maps/embed/v1/   \n",
       "1       https://api.twilio.com/2010-04-01   \n",
       "2  http://api.facebook.com/restserver.php   \n",
       "3            http://twitter.com/statuses/   \n",
       "4         http://api.flickr.com/services/   \n",
       "\n",
       "                              API Portal / Home Page  Docs Home Page URL  \\\n",
       "0                https://developers.google.com/maps/                 NaN   \n",
       "1                     https://www.twilio.com/sms/api                 NaN   \n",
       "2                   https://developers.facebook.com/                 NaN   \n",
       "3  https://developer.twitter.com/en/docs/twitter-...                 NaN   \n",
       "4                http://www.flickr.com/services/api/                 NaN   \n",
       "\n",
       "   Terms Of Service URL                 Supported Request Formats  \\\n",
       "0                   NaN    URI Query String/CRUD, VML, JavaScript   \n",
       "1                   NaN               JSON, URI Query String/CRUD   \n",
       "2                   NaN                     URI Query String/CRUD   \n",
       "3                   NaN                     URI Query String/CRUD   \n",
       "4                   NaN  URI Query String/CRUD, XML, PHP, XML-RPC   \n",
       "\n",
       "  Supported Response Formats Is This an Unofficial API?  \\\n",
       "0             JSON, KML, XML                         No   \n",
       "1                       JSON                         No   \n",
       "2    CSV, GeoJSON, JSON, XML                         No   \n",
       "3             Atom, RSS, XML                         No   \n",
       "4    JSON, XML, PHP, XML-RPC                         No   \n",
       "\n",
       "  Is the API Design/Description Non-Proprietary ?  \\\n",
       "0                                              No   \n",
       "1                                             Yes   \n",
       "2                                              No   \n",
       "3                                             Yes   \n",
       "4                                              No   \n",
       "\n",
       "  Restricted Access ( Requires Provider Approval ) Is This a Hypermedia API?  \\\n",
       "0                                               No                       Yes   \n",
       "1                                               No                        No   \n",
       "2                                               No                       Yes   \n",
       "3                                               No                       Yes   \n",
       "4                                               No                       Yes   \n",
       "\n",
       "  SSL Support Architectural Style                       Twitter URL  \\\n",
       "0          No                REST  http://twitter.com/googlemapsapi   \n",
       "1         Yes                REST        https://twitter.com/twilio   \n",
       "2         Yes                REST     http://twitter.com/fbplatform   \n",
       "3          No                FEED     http://twitter.com/twitterapi   \n",
       "4         Yes                REST        https://twitter.com/Flickr   \n",
       "\n",
       "     Authentication Model  \n",
       "0                 API Key  \n",
       "1  HTTP Basic Auth, Token  \n",
       "2        API Key, OAuth 2  \n",
       "3                 OAuth 2  \n",
       "4                 OAuth 1  "
      ]
     },
     "execution_count": 98,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "api_2.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d1b34cc-5d5f-4120-8fd9-cd4390dcc2b0",
   "metadata": {},
   "source": [
    "### Concatenate API dfs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "id": "14cfcf1b-1a5a-46b3-9b61-a799f09cbe66",
   "metadata": {},
   "outputs": [],
   "source": [
    "api_text_df_1 = api[['api_name', 'api_text']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "id": "1acad555-975d-41ab-85ee-3cb38f45e39a",
   "metadata": {},
   "outputs": [],
   "source": [
    "api_text_df_2 = api_new_df[['api_name', 'api_desc']]\n",
    "api_text_df_2.columns = ['api_name', 'api_text']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "id": "0022c2e8-1df5-4406-9c45-455f1421292c",
   "metadata": {},
   "outputs": [],
   "source": [
    "api_text_df_3 = api_2[['Name', 'Desc']]\n",
    "api_text_df_3.columns = ['api_name', 'api_text']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "id": "b8a5beb3-8310-41a1-bed6-33c340d37f9a",
   "metadata": {},
   "outputs": [],
   "source": [
    "api_text_df = api_text_df_1.append(api_text_df_2).append(api_text_df_3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "id": "6f342bb8-53b9-4850-b107-0e9c555ab622",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Before (31740, 2)\n",
      "After (22929, 2)\n"
     ]
    }
   ],
   "source": [
    "print('Before', api_text_df.shape)\n",
    "api_text_df = api_text_df.drop_duplicates('api_name')\n",
    "print('After', api_text_df.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "id": "25eb24a0-8e37-49b6-a628-d350e061baa7",
   "metadata": {},
   "outputs": [],
   "source": [
    "api_text_df = api_text_df.reset_index(drop=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d49a223a-c7b9-48de-89c0-c3928237cec9",
   "metadata": {},
   "source": [
    "### Create Mashup-API relation labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 129,
   "id": "0f33ed8f-6dd4-4382-ae97-03c5c6480c4b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "11c86f140e12429fa254f69c1c8bc87a",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/2758 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "available_apis = []\n",
    "for idx, row in tqdm(mashup_non_trivial.iterrows(), total=mashup_non_trivial.shape[0]):\n",
    "    for a in row['Related APIs']:\n",
    "        if a in api_text_df['api_name'].values:\n",
    "            available_apis.append({'mashup_name': row['mashup_name'], 'api_name': a})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 130,
   "id": "adc88a01-0d12-40fd-a203-7f933cd2a683",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>mashup_name</th>\n",
       "      <th>api_name</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Twitwhere</td>\n",
       "      <td>Twitter</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Twitwhere</td>\n",
       "      <td>Google Earth</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Twitwhere</td>\n",
       "      <td>Google App Engine</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>PetStew.com</td>\n",
       "      <td>Flickr</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>PetStew.com</td>\n",
       "      <td>Amazon Product Advertising</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   mashup_name                    api_name\n",
       "0    Twitwhere                     Twitter\n",
       "1    Twitwhere                Google Earth\n",
       "2    Twitwhere           Google App Engine\n",
       "3  PetStew.com                      Flickr\n",
       "4  PetStew.com  Amazon Product Advertising"
      ]
     },
     "execution_count": 130,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "label_df = pd.DataFrame(available_apis)\n",
    "label_df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "edfa96b3-c641-4651-8e38-adfbec89cf30",
   "metadata": {},
   "source": [
    "### Filter trivial mashup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 132,
   "id": "8b514eb2-f90a-43d1-b655-2cf75ebb1612",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Index(['3d Movie Store', 'AT&T Drive Mode for Android',\n",
       "       'AT&T Drive Mode for iOS', 'Altertunes',\n",
       "       'Amazon and SeeqPod Music Recommendations', 'Arrowpointe Maps',\n",
       "       'BeatStriker', 'Big & Bold', 'Bitcoin Exchange Rates', 'BoatTrader',\n",
       "       'Call for The Dream', 'Canadian Thor', 'CloudGento', 'Comprendo',\n",
       "       'Congress Meets Second Life', 'Cyborg Karaoke Party',\n",
       "       'Democrat or Republican', 'Drawloop LOOPlus', 'DukeTek Web Player',\n",
       "       'EVE iCEO', 'EVE iMonitor', 'EVE iPos', 'Faceforce', 'Figo in Billomat',\n",
       "       'Follow Oil Money', 'FoodieToGo', 'Fuzzy.ai for Google Sheets',\n",
       "       'Giftivo', 'Google Lyrics Gadget', 'Hundred Zeros', 'Infopia',\n",
       "       'Interactive Marine Weather Map',\n",
       "       'International AIDS Candlelight Memorial Map', 'Jaikoz Audio Tagger',\n",
       "       'LyricsFly', 'Math Quotes for Android',\n",
       "       'Mobile Search on Urban Dictionary', 'Mobile Weatherbug',\n",
       "       'Music My Music', 'MusicDB', 'Oatmeal Music for iPhone',\n",
       "       'OffersMaldives.com', 'PIG WTHR', 'PeoplePond ADAM Blogger Widget',\n",
       "       'Periodic Table of Heavy Metal', 'Phone2Lead',\n",
       "       'Postal Letters From Salesforce', 'ProgrammableWeb Member Map',\n",
       "       'Recom.me', 'Reverse Phone Search Widget', 'RingDNA softphone',\n",
       "       'SMS to Phone (Chrome Extension)', 'SalesForce and Box.net',\n",
       "       'SalesView', 'Salesforce Campaign Effectiveness Dashboard',\n",
       "       'Salesforce and Google Maps', 'Seatwave Top Artists',\n",
       "       'Sharemethods + EchoSign', 'Shorten Me!',\n",
       "       'Social Salesforce Twitter Search Widget',\n",
       "       'Spam Check: Salesforce plus Akismet', 'Surveilio Force',\n",
       "       'Urban Dictionary TV',\n",
       "       'Vanilla Forums and Google Course Builder Python Mashup',\n",
       "       'WeatherBug Maps', 'WeatherMole', 'WoMEn index', 'WrongWeather',\n",
       "       'Xendo', 'Yahoo Updates Google Gadget',\n",
       "       'ZenKraft Shipmate - FedEx for Salesforce',\n",
       "       'iGoogle EvE Training Monitor'],\n",
       "      dtype='object', name='mashup_name')"
      ]
     },
     "execution_count": 132,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "trivial_mashup_id = label_df.groupby('mashup_name').count().query('api_name < 2').index\n",
    "trivial_mashup_id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 133,
   "id": "198f5854-6e83-4577-8dab-45d39bf83c6d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Before (9032, 2)\n",
      "After (8960, 2)\n"
     ]
    }
   ],
   "source": [
    "print('Before', label_df.shape)\n",
    "label_df = label_df[~label_df['mashup_name'].isin(trivial_mashup_id)]\n",
    "print('After', label_df.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "efb15188-07d6-4f1e-aa1d-70e14a582e2d",
   "metadata": {},
   "source": [
    "### Additional Cleaning"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "id": "2f416edc-e267-4c95-90b2-f8023508684f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>api_name</th>\n",
       "      <th>api_text</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>9316</th>\n",
       "      <td>MusicMobs</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       api_name api_text\n",
       "9316  MusicMobs      NaN"
      ]
     },
     "execution_count": 143,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "api_subset[api_subset['api_text'].isna()]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 144,
   "id": "fc91d189-9806-4fdf-9ef8-da38b7d1f17f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>mashup_name</th>\n",
       "      <th>api_name</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>3144</th>\n",
       "      <td>Shareable Music Playlists</td>\n",
       "      <td>MusicMobs</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                    mashup_name   api_name\n",
       "3144  Shareable Music Playlists  MusicMobs"
      ]
     },
     "execution_count": 144,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "label_df[label_df['api_name'] == 'MusicMobs']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 145,
   "id": "041b68a2-35ca-4bfa-86b0-aff516bb4100",
   "metadata": {},
   "outputs": [],
   "source": [
    "label_df = label_df.drop(3144)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 146,
   "id": "ab7bedfb-e3e7-4f0a-97eb-032cb954fbc3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((1254, 2), (22929, 2))"
      ]
     },
     "execution_count": 146,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "api_subset = api_text_df[api_text_df['api_name'].isin(label_df['api_name'])]\n",
    "api_subset.shape, api_text_df.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 156,
   "id": "b86c8bea-a1ca-4007-95a9-a4b95a83f972",
   "metadata": {},
   "outputs": [],
   "source": [
    "mashup_subset = mashup[mashup['mashup_name'].isin(label_df['mashup_name'])]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 157,
   "id": "ada4f342-b193-490c-a847-21ab612978d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "api_subset.reset_index(drop=True, inplace=True)\n",
    "mashup_subset.reset_index(drop=True, inplace=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f5a303d5-1670-4994-9714-0d9db8f9501f",
   "metadata": {},
   "source": [
    "## TF-IDF"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59262b5e-fd37-493f-a149-4369df1119d0",
   "metadata": {},
   "source": [
    "### Training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 158,
   "id": "ee466492-39f0-43c5-b620-d4e1cab55a22",
   "metadata": {},
   "outputs": [],
   "source": [
    "all_texts = mashup_subset['Description'].values.tolist() + api_subset['api_text'].values.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 159,
   "id": "2298d102-0dec-4ece-bcc9-032b5ffc5c8c",
   "metadata": {},
   "outputs": [],
   "source": [
    "vectorizer = TfidfVectorizer(max_features=10000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 160,
   "id": "1c27d0a7-1ea0-45f0-a64b-dc385b84ee83",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "TfidfVectorizer(max_features=10000)"
      ]
     },
     "execution_count": 160,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vectorizer.fit(all_texts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 161,
   "id": "269ee000-d916-4fda-8f7d-071041e2ad63",
   "metadata": {},
   "outputs": [],
   "source": [
    "mashup_features = vectorizer.transform(mashup_subset['Description'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "id": "d910139f-c8de-4470-bba7-be7387f96709",
   "metadata": {},
   "outputs": [],
   "source": [
    "api_features = vectorizer.transform(api_subset['api_text'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "id": "f958556f-2269-40e8-8fe4-71979a0a1d93",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((2685, 10000), (1254, 10000))"
      ]
     },
     "execution_count": 163,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mashup_features.shape, api_features.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 164,
   "id": "4309535e-1b83-4450-a2ab-171ae7217d18",
   "metadata": {},
   "outputs": [],
   "source": [
    "sim = cosine_similarity(mashup_features, api_features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 165,
   "id": "e6c267ff-665b-4ee7-bf8b-f0dfdbde020e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2685, 1254)"
      ]
     },
     "execution_count": 165,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sim.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "455d2b9a-db22-47a3-a4a8-9defdd0adf09",
   "metadata": {},
   "source": [
    "### Evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 191,
   "id": "90cd0c1e-f507-4c98-b31f-5860e8ada162",
   "metadata": {},
   "outputs": [],
   "source": [
    "def recall(pred, label):\n",
    "    correct = 0\n",
    "    for p in pred:\n",
    "        if p in label:\n",
    "            correct += 1\n",
    "    return correct / len(label)\n",
    "\n",
    "def precision(pred, label):\n",
    "    correct = 0\n",
    "    for p in pred:\n",
    "        if p in label:\n",
    "            correct += 1\n",
    "    return correct / len(pred)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 193,
   "id": "8c582d11-304b-42e9-9cb0-a94821799c9d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "37ccce09d69542dcbc785a6fedf6b983",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/2685 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "topk = list(range(5, 15))\n",
    "metrics = {x: {'recall': 0, 'precision': 0, 'f1': 0} for x in topk}\n",
    "for idx, row in tqdm(mashup_subset.iterrows(), total=mashup_subset.shape[0]):\n",
    "    ground_truth = label_df[label_df['mashup_name'] == row['mashup_name']]['api_name']\n",
    "    gt_idx = api_subset[api_subset['api_name'].isin(ground_truth)].index\n",
    "#     print(gt_idx)\n",
    "    for n in topk:\n",
    "        pred = sim[idx].argsort()[-n:][::-1]\n",
    "        recall_ = recall(pred, gt_idx)\n",
    "        prec_ = precision(pred, gt_idx)\n",
    "        if recall_ + prec_ != 0:\n",
    "            f1 = (2 * recall_ * prec_) / (recall_ + prec_)\n",
    "        else:\n",
    "            f1 = 0\n",
    "        metrics[n]['recall'] += recall_ / mashup_subset.shape[0]\n",
    "        metrics[n]['precision'] += prec_ / mashup_subset.shape[0]\n",
    "        metrics[n]['f1'] += f1 / mashup_subset.shape[0]\n",
    "#         print(n, pred, recall(pred, gt_idx))\n",
    "#     break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 194,
   "id": "c8d9539a-e9f6-4876-9887-823f18f9c6ce",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{5: {'recall': 0.2576874582989286,\n",
       "  'precision': 0.13675977653631116,\n",
       "  'f1': 0.17175270161215442},\n",
       " 6: {'recall': 0.2783285701355721,\n",
       "  'precision': 0.12389819987585339,\n",
       "  'f1': 0.16483960293939226},\n",
       " 7: {'recall': 0.29477681152794866,\n",
       "  'precision': 0.113540835328543,\n",
       "  'f1': 0.1576528933960997},\n",
       " 8: {'recall': 0.3083373646886199,\n",
       "  'precision': 0.10460893854748879,\n",
       "  'f1': 0.15028395003176384},\n",
       " 9: {'recall': 0.32058936884006617,\n",
       "  'precision': 0.09741361473204992,\n",
       "  'f1': 0.1437557019107129},\n",
       " 10: {'recall': 0.33152147451195485,\n",
       "  'precision': 0.09109869646182507,\n",
       "  'f1': 0.1375829692345779},\n",
       " 11: {'recall': 0.34062814667910846,\n",
       "  'precision': 0.08555950567123918,\n",
       "  'f1': 0.13172014188586179},\n",
       " 12: {'recall': 0.35007599037276255,\n",
       "  'precision': 0.08066418373680936,\n",
       "  'f1': 0.12647366817971806},\n",
       " 13: {'recall': 0.3578966323833488,\n",
       "  'precision': 0.07640739149118997,\n",
       "  'f1': 0.12158262694384663},\n",
       " 14: {'recall': 0.36514162001216843,\n",
       "  'precision': 0.07254588986432471,\n",
       "  'f1': 0.1169614530315595}}"
      ]
     },
     "execution_count": 194,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "metrics"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a58e0445-1e4c-4121-9a71-baf95bd1e861",
   "metadata": {},
   "source": [
    "## Word2vec"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53986822-434a-4ae8-a3c1-6011cabd5a44",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de617da8-2386-4cb6-b247-dd0031685176",
   "metadata": {},
   "source": [
    "## LSTM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 195,
   "id": "1949d599-e05e-4a53-a197-3c9c07cc9ea6",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch import nn"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30162124-8e7b-47cc-9239-66cd7a2c0b42",
   "metadata": {},
   "source": [
    "## Doc2Vec"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 197,
   "id": "12dbc13f-5419-4d87-9a36-0fe02791b861",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[nltk_data] Downloading package punkt to\n",
      "[nltk_data]     C:\\Users\\Ray\\AppData\\Roaming\\nltk_data...\n",
      "[nltk_data]   Unzipping tokenizers\\punkt.zip.\n"
     ]
    }
   ],
   "source": [
    "import nltk\n",
    "nltk.set_proxy('http://127.0.0.1:18080')\n",
    "nltk.download('punkt')\n",
    "from nltk.tokenize import word_tokenize\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 200,
   "id": "db43586c-1397-4f45-be69-8bbb2ed35730",
   "metadata": {},
   "outputs": [],
   "source": [
    "tokenized_sent = []\n",
    "for s in all_texts:\n",
    "    tokenized_sent.append(word_tokenize(s.lower()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 201,
   "id": "ed6746fd-4a79-4d69-b381-c469041932c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "def cosine(u, v):\n",
    "    return np.dot(u, v) / (np.linalg.norm(u) * np.linalg.norm(v))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 204,
   "id": "8c2d81a3-4255-492a-82a5-f4ffb3fc18f3",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\anaconda3\\envs\\mashup\\lib\\site-packages\\gensim\\similarities\\__init__.py:15: UserWarning: The gensim.similarities.levenshtein submodule is disabled, because the optional Levenshtein package <https://pypi.org/project/python-Levenshtein/> is unavailable. Install Levenhstein (e.g. `pip install python-Levenshtein`) to suppress this warning.\n",
      "  warnings.warn(msg)\n"
     ]
    }
   ],
   "source": [
    "from gensim.models.doc2vec import Doc2Vec, TaggedDocument\n",
    "tagged_data = [TaggedDocument(d, [i]) for i, d in enumerate(tokenized_sent)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 220,
   "id": "54c4488f-ddc5-40de-a570-e9c88c93b265",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\nvector_size = Dimensionality of the feature vectors.\\nwindow = The maximum distance between the current and predicted word within a sentence.\\nmin_count = Ignores all words with total frequency lower than this.\\nalpha = The initial learning rate.\\n'"
      ]
     },
     "execution_count": 220,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model = Doc2Vec(tagged_data, vector_size = 100, window = 2, min_count = 1, epochs = 100)\n",
    "\n",
    "'''\n",
    "vector_size = Dimensionality of the feature vectors.\n",
    "window = The maximum distance between the current and predicted word within a sentence.\n",
    "min_count = Ignores all words with total frequency lower than this.\n",
    "alpha = The initial learning rate.\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 221,
   "id": "70a4e15b-f870-4c2c-8521-bbb86a79ec2a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "a172ec1ab77a4ba58c1bf665fb5b1de1",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/2685 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "topk = list(range(5, 15))\n",
    "metrics = {x: {'recall': 0, 'precision': 0, 'f1': 0} for x in topk}\n",
    "for idx, row in tqdm(mashup_subset.iterrows(), total=mashup_subset.shape[0]):\n",
    "    ground_truth = label_df[label_df['mashup_name'] == row['mashup_name']]['api_name']\n",
    "    gt_idx = api_subset[api_subset['api_name'].isin(ground_truth)].index\n",
    "#     print(gt_idx)\n",
    "    preds = model.dv.most_similar(positive=[model.infer_vector(word_tokenize(row['Description'].lower()))], topn=15,\n",
    "                                  clip_start=mashup_subset.shape[0])\n",
    "    preds = [p[0] - mashup_subset.shape[0] for p in preds]\n",
    "#     print(preds)\n",
    "    for n in topk:\n",
    "        pred = preds[:n]\n",
    "        recall_ = recall(pred, gt_idx)\n",
    "        prec_ = precision(pred, gt_idx)\n",
    "        if recall_ + prec_ != 0:\n",
    "            f1 = (2 * recall_ * prec_) / (recall_ + prec_)\n",
    "        else:\n",
    "            f1 = 0\n",
    "        metrics[n]['recall'] += recall_ / mashup_subset.shape[0]\n",
    "        metrics[n]['precision'] += prec_ / mashup_subset.shape[0]\n",
    "        metrics[n]['f1'] += f1 / mashup_subset.shape[0]\n",
    "#         print(n, pred, recall(pred, gt_idx))\n",
    "#     break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 222,
   "id": "ce435543-6f62-40e7-9a06-f8e099a0f6b2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{5: {'recall': 0.02887932883978163,\n",
       "  'precision': 0.01646182495344512,\n",
       "  'f1': 0.019766604407194528},\n",
       " 6: {'recall': 0.03223440124513336,\n",
       "  'precision': 0.015642458100558646,\n",
       "  'f1': 0.01983695911113581},\n",
       " 7: {'recall': 0.03532436698708727,\n",
       "  'precision': 0.0148443735035913,\n",
       "  'f1': 0.019678811396699785},\n",
       " 8: {'recall': 0.03929825054197641,\n",
       "  'precision': 0.014618249534450638,\n",
       "  'f1': 0.02009436288386081},\n",
       " 9: {'recall': 0.043326213061559024,\n",
       "  'precision': 0.014318228843368558,\n",
       "  'f1': 0.02036083182554469},\n",
       " 10: {'recall': 0.04677068706469225,\n",
       "  'precision': 0.013854748603352021,\n",
       "  'f1': 0.020281130647718415},\n",
       " 11: {'recall': 0.049688839055469926,\n",
       "  'precision': 0.013407821229050243,\n",
       "  'f1': 0.020052796331482364},\n",
       " 12: {'recall': 0.05280611180961418,\n",
       "  'precision': 0.013159528243327114,\n",
       "  'f1': 0.02004019987447663},\n",
       " 13: {'recall': 0.055677442837369806,\n",
       "  'precision': 0.012834837415843082,\n",
       "  'f1': 0.01989991782966105},\n",
       " 14: {'recall': 0.05910541795152416,\n",
       "  'precision': 0.012636339451981919,\n",
       "  'f1': 0.019887418651476647}}"
      ]
     },
     "execution_count": 222,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "metrics"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "714650be-b6fe-438a-8dc6-389a4df27de7",
   "metadata": {},
   "source": [
    "## BERT-based Unsupervised"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ecc11f06-e2ab-408b-bd99-1c72540ae897",
   "metadata": {},
   "source": [
    "### Utils"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 247,
   "id": "012e92d5-e8f2-4e80-bd72-9fd16202ffa1",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Mean Pooling - Take attention mask into account for correct averaging\n",
    "def mean_pooling(model_output, attention_mask):\n",
    "    token_embeddings = model_output[0] #First element of model_output contains all token embeddings\n",
    "    input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()\n",
    "    sum_embeddings = torch.sum(token_embeddings * input_mask_expanded, 1)\n",
    "    sum_mask = torch.clamp(input_mask_expanded.sum(1), min=1e-9)\n",
    "    return sum_embeddings / sum_mask\n",
    "\n",
    "def extract_features(sentences, model_dir):\n",
    "    tokenizer = AutoTokenizer.from_pretrained(model_dir)\n",
    "    model = AutoModel.from_pretrained(model_dir)\n",
    "\n",
    "    features = []\n",
    "    text_batchs = np.array_split(sentences, len(all_texts) // 8)\n",
    "    for batch in tqdm(text_batchs):\n",
    "        #Tokenize sentences\n",
    "        # print(batch)\n",
    "        encoded_input = tokenizer(batch.tolist(), padding=True, truncation=True, max_length=128, return_tensors='pt')\n",
    "\n",
    "        #Compute token embeddings\n",
    "        with torch.no_grad():\n",
    "            model_output = model(**encoded_input)\n",
    "\n",
    "        #Perform pooling. In this case, mean pooling\n",
    "        sentence_embeddings = mean_pooling(model_output, encoded_input['attention_mask'])\n",
    "        features.append(sentence_embeddings)\n",
    "    return torch.cat(features)\n",
    "\n",
    "def evaluate_features(features):\n",
    "    api_features = features[mashup_subset.shape[0]:]\n",
    "    mashup_features = features[:mashup_subset.shape[0]]\n",
    "    sim = cosine_similarity(mashup_features, api_features)\n",
    "    topk = list(range(5, 15))\n",
    "    metrics = {x: {'recall': 0, 'precision': 0, 'f1': 0} for x in topk}\n",
    "    for idx, row in tqdm(mashup_subset.iterrows(), total=mashup_subset.shape[0]):\n",
    "        ground_truth = label_df[label_df['mashup_name'] == row['mashup_name']]['api_name']\n",
    "        gt_idx = api_subset[api_subset['api_name'].isin(ground_truth)].index\n",
    "        for n in topk:\n",
    "            pred = sim[idx].argsort()[-n:][::-1]\n",
    "            recall_ = recall(pred, gt_idx)\n",
    "            prec_ = precision(pred, gt_idx)\n",
    "            if recall_ + prec_ != 0:\n",
    "                f1 = (2 * recall_ * prec_) / (recall_ + prec_)\n",
    "            else:\n",
    "                f1 = 0\n",
    "            metrics[n]['recall'] += recall_ / mashup_subset.shape[0]\n",
    "            metrics[n]['precision'] += prec_ / mashup_subset.shape[0]\n",
    "            metrics[n]['f1'] += f1 / mashup_subset.shape[0]\n",
    "    return metrics"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de2fd17c-e3c3-460e-b692-67538cac1842",
   "metadata": {},
   "source": [
    "### SentenceBERT"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d23e281c-6109-416e-8eba-1915c383c099",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Some weights of the model checkpoint at D:/transformers_models/bert-base-nli-mean-tokens were not used when initializing BertModel: ['classifier.bias', 'classifier.weight']\n",
      "- This IS expected if you are initializing BertModel from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n",
      "- This IS NOT expected if you are initializing BertModel from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "1347cde0d20442a7b145220d4b478a7e",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/492 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "features = extract_features(all_texts, 'D:/transformers_models/bert-base-nli-mean-tokens')\n",
    "metrics = evaluate_features(evaluate_features)\n",
    "metrics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5b0f1bc2-2f0d-4274-b60c-4fd9600d7782",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
